package com.xmim.server.examples;

import com.xmim.fulcrum.cache.AbstractFulcrumPathCache;
import com.xmim.fulcrum.node.DefaultFulcrumNode;
import com.xmim.fulcrum.node.FulcrumNode;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.apache.zookeeper.CreateMode;

import java.io.IOException;

@Slf4j
public abstract class ZkFulcrumPathCache<T extends FulcrumNode> extends AbstractFulcrumPathCache<T> {

    protected final CuratorFramework client;
    protected final ZKFulcrumDiscover discover;
    protected PathChildrenCache childrenCache;


    public ZkFulcrumPathCache(ZKFulcrumDiscover discover) {
        super(discover.getFactory());
        this.discover = discover;
        this.client = discover.getClient();
    }

    @Override
    public void init(Class<? extends FulcrumNode> clazz) {
        try {
            client.create()
                    .creatingParentsIfNeeded()
                    .withProtection()
                    .withMode(CreateMode.PERSISTENT)
                    .forPath(getPath());

            //订阅节点的增加和删除事件
            this.childrenCache = new PathChildrenCache(client, this.getPath(), true);
            PathChildrenCacheListener childrenCacheListener = new PathChildrenCacheListener() {
                @Override
                public void childEvent(CuratorFramework client, PathChildrenCacheEvent event) {
                    log.debug("开始监听的子节点：path={} class={} event{}", ZkFulcrumPathCache.this.getPath(), clazz, event.getType());
                    if (event.getData() == null || event.getData().getData() == null) {
                        log.debug("节点数据为空, event={}", event);
                        return;
                    }
                    String path = event.getData().getPath();
                    byte[] data = event.getData().getData();
                    FulcrumNode fulcrumNode = getFulcrumFactory().getCodec().decode(data, clazz);
                    switch (event.getType()) {
                        case CHILD_ADDED:
                            log.debug("添加节点：path={} class={}  data={}", path, clazz, fulcrumNode);
                            if (fulcrumNode.getId() != null) {
                                fulcrumNodeListener.onAdd(path, fulcrumNode);
                                nodeMap.put(fulcrumNode.getId().toString(), (T) fulcrumNode);
                            }
                            break;
                        case CHILD_REMOVED:
                            log.debug("删除节点：path={} class={}  data={}", path, clazz, fulcrumNode);
                            if (fulcrumNode.getId() != null) {
                                fulcrumNodeListener.onRemove(path, fulcrumNode);
                                nodeMap.remove(fulcrumNode.getId().toString());
                            }
                            break;
                        case CHILD_UPDATED:
                            log.debug("修改节点：path={} class={}  data={}", path, clazz, fulcrumNode);
                            if (fulcrumNode.getId() != null) {
                                fulcrumNodeListener.onUpdate(path, fulcrumNode);
                                nodeMap.put(fulcrumNode.getId().toString(), (T) fulcrumNode);
                            }
                            break;
                        default:
                            break;
                    }
                }
            };
            childrenCache.getListenable().addListener(childrenCacheListener);
            childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @Override
    public void close() {
        try {
            childrenCache.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @Override
    protected void onAddNode(T node) {
        try {
            String path = this.client.create()
                    .creatingParentsIfNeeded()
                    .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                    .forPath(this.getSerialPath(), null);
            long id = getFulcrumFactory().getIdByPath(path);
            if (node instanceof DefaultFulcrumNode) {
                DefaultFulcrumNode fulcrumNode = ((DefaultFulcrumNode) node);
                fulcrumNode.setId(id);
                fulcrumNode.setPath(path);
                byte[] encode = getFulcrumFactory().getCodec().encode(fulcrumNode);
                this.client.setData().forPath(path, encode);
            }
            log.debug("添加节点成功：path={} node={}", this.getPath(), node);
        } catch (Exception e) {
            log.error("添加节点失败：path={} node={}" + this.getPath() + node, e);
        }

    }

    @Override
    protected void onRemoveNode(String id) {

    }


}
